package band.wukong.practice.javase.core.thread.communicate;

/**
 * Desc: 生产者与消费者的问题。线程通讯
 * Author: sunjs
 * Date: 2009-11-9 16:55:55
 */
public class TestProducerAndConsumer {
    protected static final int LOOP_TIMES = 200;

    public static void main(String[] args) {
//        Stack stack01 = new Stack("stack01");
//        Producer producer1 = new Producer(stack01, "producer1");
//        Consumer consumer1 = new Consumer(stack01, "consumer1");
//        Consumer consumer2 = new Consumer(stack01, "consumer2");

        Stack stack02 = new Stack("stack02");
        Producer producer2 = new Producer(stack02, "producer2");
        Producer producer3 = new Producer(stack02, "producer3");
        Consumer consumer3 = new Consumer(stack02, "consumer3");
    }
}


class Producer extends Thread {
    private Stack stack;

    public Producer(Stack s, String name) {
        super(name);
        stack = s;
        start();
    }

    public void run() {
        String goods;
        for (int i = 0; i < TestProducerAndConsumer.LOOP_TIMES; i++) {
            synchronized (stack) {
                goods = "goods" + (stack.getPoint() + 1);
                stack.push(goods);
                System.out.println(getName() + ": push " + goods);
            }
        }
    }
}

class Consumer extends Thread {
    private Stack stack;

    public Consumer(Stack s, String name) {
        super(name);
        stack = s;
        start();
    }

    public void run() {
        String goods = null;
        for (int i = 0; i < TestProducerAndConsumer.LOOP_TIMES; i++) {
            goods = stack.pop();
            System.out.println(getName() + ": pop " + goods + " from " + stack.getName());
            yield();
        }
    }
}

class Stack {
    int point = -1;
    private String name;
    private String[] buffer = new String[200];

    public Stack(String name) {
        this.name = name;
    }

    public synchronized String pop() {
        this.notifyAll();
        while (point == -1) {
            System.out.println(Thread.currentThread().getName() + ": wait.");
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        String goods = buffer[point];
        buffer[point] = null;
        Thread.yield();
        point--;
        return goods;
    }

    public synchronized void push(String goods) {
        this.notifyAll();
        while (point == buffer.length - 1) {
            System.out.println(Thread.currentThread().getName() + ": wait.");
            try {
                this.wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        point++;
        Thread.yield();
        buffer[point] = goods;
    }

    public String getName() {
        return name;
    }

    public synchronized int getPoint() {
        return point;
    }
}